package com.javajun.endofterm.security;

import com.javajun.endofterm.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Set;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * Author: Xiong Limin
 * Date: 2020-11-26-12:05 下午
 */
@Configuration
@EnableWebSecurity
// Spring Security默认是禁用注解的
// 要想开启注解，需要在继承WebSecurityConfigurerAdapter的类上加@EnableGlobalMethodSecurity注解
// 来判断用户对某个控制层的方法是否具有访问权限
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SysUserService sysUserService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                // 设置服务类，以及密码加密
        auth.userDetailsService(sysUserService).passwordEncoder(new BCryptPasswordEncoder());
        // 在内存中添加用户
        auth.inMemoryAuthentication().withUser("秦源").password("{noop}1111") // noop 表示明文
                .roles("DVP", "ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

                /* 在Security的默认拦截器里，默认会开启CSRF处理，判断请求是否携带了token，如果没有就拒绝访问 */
        http.authorizeRequests()
                // 配置路径拦截
                // 静态资源所有用户均可访问
                // favicon.ico图标允许所用用户可以使用
                .antMatchers("/favicon.ico").permitAll()
                // 放行所有请求（为了在开发时方便测试）
                // .antMatchers("/**").permitAll()

                // 其他地址的访问均需验证权限（需要登录）
                .anyRequest().authenticated().and()
                // 登录相关
                .formLogin().loginPage("/login").permitAll() //登录页面
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                        Set<String> roles = AuthorityUtils.authorityListToSet(authentication.getAuthorities());
                        String url = "";
                        if (roles.contains("ROLE_ADMIN")) {
                            url = "main";
                        } else  if (roles.contains("ROLE_STUDENT")) {
                            url = "home";
                        }

                        httpServletResponse.setContentType("application/json;charset=utf-8");
                        PrintWriter out = httpServletResponse.getWriter();
                        out.write("{\"code\":\"0\",\"msg\":\"登录成功\",\"url\":\""+url+"\"}");
                        out.flush();
                        out.close();
                    }
                })
                // 登录失败页面
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
                        httpServletResponse.setContentType("application/json;charset=utf-8");
                        PrintWriter out = httpServletResponse.getWriter();
                        out.write("{\"code\":\"-1\",\"msg\":\"登录失败\",\"url\":\"login?erro=failed\"}");
                        out.flush();
                        out.close();
                    }
                })
                .and()
                // 注销相关
                .logout()
                // 注销页面
                .logoutUrl("/logout").permitAll().and()
                // 允许跨域访问
                .headers().frameOptions().disable().and()
                // 关闭 CSRF
                .csrf().disable()
                // 开启basic认证，若不添加此项，将不能通过curl的basic方式传递用户信息
                .httpBasic();

        /*http.authorizeRequests()
                .anyRequest().permitAll()
                .and().headers()
                .frameOptions().sameOrigin()
                .httpStrictTransportSecurity().disable()
                .and()
                .csrf().disable();*/
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 静态资绕过 Spring Security 的所有 Filter
        web.ignoring().antMatchers("/api/**", "/css/**", "/images/**", "/js/**", "/lib/**");
    }
}
